#include <fstream>
#include "WildernessEscape.h"
#include "GameSingleton.h"
#include "Log.h"
#include "Expand/PluginsManager.h"
#include "Expand/EventManager.h"
#include "Managers/GameManager.h"
#include "Managers/BlocksManager.h"

#include "Subsystems/SubsystemTerrain.h"
#include "SubsystemBedWarsTerrain.h"
#include "SubsystemBedWarsRotBlockBehavior.h"
#include "SubsystemBedWarsChestBlockBehavior.h"

#include "Utils/Utils.h"
#include "nlohmann/json.hpp"
#include "Network/Client.h"
#include "Player/PlayerData.h"
#include "Components/ComponentPlayer.h"
#include "Components/ComponentBody.h"
#include "Components/ComponentClothing.h"
#include "Components/ComponentHealth.h"


namespace WE
{

    static const std::string titleText = "WildernessEscapeCore";

    WildernessEscapeCore::WildernessEscapeCore()
    {
        // m_inventoryEvent = new InventoryEvent(this);
        // PocketSurvival::GameSingleton::eventManager->addEvent<IInventoryEvent>(m_inventoryEvent);
        // PocketSurvival::GameSingleton::eventManager->addEvent<IInventoryOpenEvent>(m_inventoryEvent);

        // m_playerEvent = new PlayerEvent(this);
        // PocketSurvival::GameSingleton::eventManager->addEvent<IPlayerEvent>(m_playerEvent);
        // PocketSurvival::GameSingleton::eventManager->addEvent<ICreatureEvent>(m_playerEvent);

        // m_signEvent = new SignEvent(this);
        // PocketSurvival::GameSingleton::eventManager->addEvent<ISignEvent>(m_signEvent);

        // bedWarsTerrain = PocketSurvival::GameSingleton::gameManager->replaceSubsystem<SubsystemTerrain, SubsystemBedWarsTerrain>();
        // bedWarsTerrain->bedWaresCore = this;
        // // 注册子系统
        // subsystemBedWars = PocketSurvival::GameSingleton::gameManager->registerSubsystem<SubsystemBedWars>();
        // subsystemBedWars->bedWarsCore = this;

        // 关闭食物腐烂
        // PocketSurvival::GameSingleton::gameManager->replaceSubsystem<SubsystemRotBlockBehavior, SubsystemBedWarsRotBlockBehavior>();
    }


    void WildernessEscapeCore::processCmd(ChatObj &chatObj, std::vector<std::string> &cmdDataVec)
    {
        if(cmdDataVec.size() == 2)
        {
            if(cmdDataVec[1] == "list")
            {
                std::stringstream ss;
                ss << "队伍人数详情如下\n红:";
                for(entt::entity entity : subsystemBedWars->teamEntitySet[0])
                {
                    ss << (uint16_t)entity << " , ";
                }
                ss << "\n蓝:";
                for(entt::entity entity : subsystemBedWars->teamEntitySet[1])
                {
                    ss << (uint16_t)entity << " , ";
                }
                ss << "\n绿:";
                for(entt::entity entity : subsystemBedWars->teamEntitySet[2])
                {
                    ss << (uint16_t)entity << " , ";
                }
                ss << "\n紫:";
                for(entt::entity entity : subsystemBedWars->teamEntitySet[3])
                {
                    ss << (uint16_t)entity << " , ";
                }
                chatObj.sendMessage(titleText, ss.str());
                return;
            }
            else if(cmdDataVec[1] == "edit")
            {
                isEditMode = !isEditMode;
                if(isEditMode == true)
                {
                    chatObj.sendMessage(titleText, "开启编辑模式");
                }
                else
                {
                    std::lock_guard<std::mutex> lk(m_setRanksHomeMutex);
                    m_setTeamHomeMap.clear();
                    subsystemBedWars->changeStatue(BedWarsStatue::Prepare);
                    chatObj.sendMessage(titleText, "关闭编辑模式");
                }
                return;
            }
            else if(cmdDataVec[1] == "respawn")
            {
                respawnPosition = chatObj.m_client->playerData->componentPlayer->componentBody->position;
                chatObj.sendMessage(titleText, fmt::format("成功设置观众的出生点为 {},{},{}", respawnPosition.posX, respawnPosition.posY, respawnPosition.posZ));
                return;
            }
            else if(cmdDataVec[1] == "prepare")
            {
                if(isEditMode == false)
                {
                    subsystemBedWars->changeStatue(BedWarsStatue::Prepare);
                    chatObj.sendMessage(titleText, "强制游戏到等待状态");
                }
                else
                {
                    chatObj.sendMessage(titleText, "编辑模式下无效");
                }
                return;
            }
            else if(cmdDataVec[1] == "run")
            {
                if(isEditMode == false)
                {
                    subsystemBedWars->changeStatue(BedWarsStatue::GameRunning);
                    chatObj.sendMessage(titleText, "强制游戏到运行状态");
                }
                else
                {
                    chatObj.sendMessage(titleText, "编辑模式下无效");
                }
                return;
            }
            else if(cmdDataVec[1] == "countdown")
            {
                if(isEditMode == false)
                {
                    subsystemBedWars->changeStatue(BedWarsStatue::Countdown);
                    chatObj.sendMessage(titleText, "强制游戏到倒计时状态");
                }
                else
                {
                    chatObj.sendMessage(titleText, "编辑模式下无效");
                }
                return;
            }
            else if(cmdDataVec[1] == "end")
            {
                if(isEditMode == false)
                {
                    subsystemBedWars->changeStatue(BedWarsStatue::Ending);
                    chatObj.sendMessage(titleText, "强制游戏到结束状态");
                }
                else
                {
                    chatObj.sendMessage(titleText, "编辑模式下无效");
                }
                return;
            }
            else if(cmdDataVec[1] == "reterrain")
            {
                subsystemBedWars->terrainClear();
                chatObj.sendMessage(titleText, "地形重置成功");
                return;
            }
            else if(cmdDataVec[1] == "source")
            {
                subsystemBedWars->produceSourcePickable(5);
                chatObj.sendMessage(titleText, "生产资源成功");
                return;
            }
        }
        if(cmdDataVec.size() == 3)
        {
            if(cmdDataVec[1] == "height")
            {
                limitHeight = atoi(cmdDataVec[2].c_str());
                chatObj.sendMessage(titleText, fmt::format("成功将高度限制设置为 : {}", limitHeight));
                return; 
            }
            if(chatObj.m_isTerminal == true)
            {
                chatObj.sendMessage(titleText,"控制台不能使用该指令");
                return;
            }
            if(cmdDataVec[1] == "join")
            {
                if(chatObj.m_isTerminal == true)
                {
                    chatObj.sendMessage(titleText, "该指令不能在控制台使用");
                    return;
                }
                ComponentPlayer *componentPlayer = chatObj.m_client->playerData->componentPlayer;
                if(cmdDataVec[2] == "red")
                {
                    componentPlayer->componentHealth->invincibleTime = 1.5f; 
                    subsystemBedWars->resetPlayer(componentPlayer);
                    subsystemBedWars->setTeamClothes(componentPlayer, TeamType::Red);
                    subsystemBedWars->joinTeam(componentPlayer->entity, TeamType::Red);
                    subsystemBedWars->toTeamHomePosition(componentPlayer);
                    chatObj.sendMessage(titleText, "强制加入红队");
                    return;
                }
                else if(cmdDataVec[2] == "blue")
                {
                    componentPlayer->componentHealth->invincibleTime = 1.5f; 
                    subsystemBedWars->resetPlayer(componentPlayer);
                    subsystemBedWars->setTeamClothes(componentPlayer, TeamType::Blue);
                    subsystemBedWars->joinTeam(componentPlayer->entity, TeamType::Blue);
                    subsystemBedWars->toTeamHomePosition(componentPlayer);
                    chatObj.sendMessage(titleText, "强制加入蓝队");
                    return;
                }
                else if(cmdDataVec[2] == "green")
                {
                    componentPlayer->componentHealth->invincibleTime = 1.5f; 
                    subsystemBedWars->resetPlayer(componentPlayer);
                    subsystemBedWars->setTeamClothes(componentPlayer, TeamType::Green);
                    subsystemBedWars->joinTeam(componentPlayer->entity, TeamType::Green);
                    subsystemBedWars->toTeamHomePosition(componentPlayer);
                    chatObj.sendMessage(titleText, "强制加入绿队");
                    return;
                }
                else if(cmdDataVec[2] == "purple")
                {
                    componentPlayer->componentHealth->invincibleTime = 1.5f; 
                    subsystemBedWars->resetPlayer(componentPlayer);
                    subsystemBedWars->setTeamClothes(componentPlayer, TeamType::Purple);
                    subsystemBedWars->joinTeam(componentPlayer->entity, TeamType::Purple);
                    subsystemBedWars->toTeamHomePosition(componentPlayer);
                    chatObj.sendMessage(titleText, "强制加入紫队");
                    return;
                }
            }


            if(isEditMode == false)
            {
                chatObj.sendMessage(titleText, "请先开启编辑模式");
                return;
            }
            Vector3 position;
            if(cmdDataVec[1] == "red")
            {
                if(cmdDataVec[2] == "position")
                {
                    position = chatObj.m_client->playerData->componentPlayer->componentBody->position;
                    teamData[0].startPosition = position;
                    chatObj.sendMessage(titleText, fmt::format("成功设置红队的出生点为 {},{},{}", position.posX, position.posY, position.posZ));
                    return;
                }
                if(cmdDataVec[2] == "home")
                {
                    std::lock_guard<std::mutex> lk(m_setRanksHomeMutex);
                    uint16_t key = (uint16_t)chatObj.m_client->playerData->entity;
                    m_setTeamHomeMap[key] = TeamType::Red;
                    chatObj.sendMessage(titleText, "放置十字坟碑设置红队的核心点");
                    return;
                }
            }
            if(cmdDataVec[1] == "blue")
            {
                if(cmdDataVec[2] == "position")
                {
                    position = chatObj.m_client->playerData->componentPlayer->componentBody->position;
                    teamData[1].startPosition = position;
                    chatObj.sendMessage(titleText, fmt::format("成功设置蓝队的出生点为 {},{},{}", position.posX, position.posY, position.posZ));
                    return;
                }
                if(cmdDataVec[2] == "home")
                {
                    std::lock_guard<std::mutex> lk(m_setRanksHomeMutex);
                    uint16_t key = (uint16_t)chatObj.m_client->playerData->entity;
                    m_setTeamHomeMap[key] = TeamType::Blue;
                    chatObj.sendMessage(titleText, "\n放置十字坟碑设置蓝队的核心点");
                    return;
                }
            }
            if(cmdDataVec[1] == "green")
            {
                if(cmdDataVec[2] == "position")
                {
                    position = chatObj.m_client->playerData->componentPlayer->componentBody->position;
                    teamData[2].startPosition = position;
                    chatObj.sendMessage(titleText, fmt::format("成功设置绿队的出生点为 {},{},{}", position.posX, position.posY, position.posZ));
                    return;
                }
                if(cmdDataVec[2] == "home")
                {
                    std::lock_guard<std::mutex> lk(m_setRanksHomeMutex);
                    uint16_t key = (uint16_t)chatObj.m_client->playerData->entity;
                    m_setTeamHomeMap[key] = TeamType::Green;
                    chatObj.sendMessage(titleText, "放置十字坟碑设置绿队的核心点");
                    return;
                }
            }
            if(cmdDataVec[1] == "purple")
            {
                if(cmdDataVec[2] == "position")
                {
                    position = chatObj.m_client->playerData->componentPlayer->componentBody->position;
                    teamData[3].startPosition = position;
                    chatObj.sendMessage(titleText, fmt::format("成功设置紫队的出生点为 {},{},{}", position.posX, position.posY, position.posZ));
                    return;
                }
                if(cmdDataVec[2] == "home")
                {
                    std::lock_guard<std::mutex> lk(m_setRanksHomeMutex);
                    uint16_t key = (uint16_t)(chatObj.m_client->playerData->entity);
                    m_setTeamHomeMap[key] = TeamType::Purple;
                    chatObj.sendMessage(titleText, "放置十字坟碑设置紫队的核心点");
                    return;
                }
            }
        }
        chatObj.sendMessage(titleText, "\n/bedwars edit - 开启或关闭编辑模式\n/bedwars respawn - 设置大厅出生点\n/bedwars height (高度) - 设置观众台与游戏的高度区分");
    }

    void WildernessEscapeCore::load()
    {
        PocketSurvival::GameSingleton::blocksManager->blocks[15]->ProjectileResilience = 1.0f;     // 玻璃
        PocketSurvival::GameSingleton::blocksManager->blocks[44]->ProjectileResilience = 1.0f;     // 玻璃框
        PocketSurvival::GameSingleton::blocksManager->blocks[60]->ProjectileResilience = 1.0f;     // 玻璃窗户
        PocketSurvival::GameSingleton::blocksManager->blocks[68]->ProjectileResilience = 1.0f;     // 大理石
        PocketSurvival::GameSingleton::blocksManager->blocks[69]->ProjectileResilience = 1.0f;     // 大理石台阶
        PocketSurvival::GameSingleton::blocksManager->blocks[70]->ProjectileResilience = 1.0f;     // 大理石半砖
        PocketSurvival::GameSingleton::blocksManager->blocks[258]->ProjectileResilience = 1.0f;    // 十字坟碑

        PocketSurvival::GameSingleton::blocksManager->blocks[45]->FireDuration = 0.0f;             // 箱子不会着火
        PocketSurvival::GameSingleton::blocksManager->blocks[126]->FireDuration = 0.0f;            // 钻石块方块不会着火

        std::ifstream stream;
        stream.open("./Plugins/BedWars/BedWars.json");
        if(stream.is_open())
        {
            nlohmann::json jsonData;
            stream >> jsonData;

            isEditMode = jsonData["IsEditMode"].get<bool>();
            respawnPosition = jsonData["RespawnPosition"].get<Point3>();
            teamPlayerCount = jsonData["TeamPlayerCount"].get<uint8_t>();
            limitHeight = jsonData["LimitHeight"].get<int32_t>();
            bedBreakCount = jsonData["BedBreakCount"].get<uint8_t>();
            resourceSet = jsonData["Resource"].get<std::set<Point3>>();

            limitCoordStart = jsonData["LimitCoordStart"].get<Point2>();
            limitCoordEnd = jsonData["LimitCoordEnd"].get<Point2>();

            nlohmann::json &ranksDataJson = jsonData["RanksData"];
            for(uint8_t index = 0; index < 4; index++)
            {
                teamData[index].joinSignPoint = ranksDataJson[index]["JoinSignPoint"].get<Point3>();
                teamData[index].startPosition = ranksDataJson[index]["StartPoint"].get<Point3>();
                teamData[index].bedPoint = ranksDataJson[index]["BedPoint"].get<Point3>();
                teamData->playerVec.reserve(teamPlayerCount);
            }
        }
        stream.close();
    }

    void WildernessEscapeCore::save()
    {
        const std::string pluginDataPath = "./Plugins/WildernessEscape";
        if(std::filesystem::exists(pluginDataPath) == false)
        {
            if(std::filesystem::create_directories(pluginDataPath) == false)
            {
                throw std::runtime_error("检测不到 [荒野逃生] 数据文件夹，并且无法创建新的 [荒野逃生] 数据文件夹");
            }
        }
        nlohmann::json jsonData = {
            { "IsEditMode", isEditMode },
            { "RespawnPosition", respawnPosition },
            { "TeamPlayerCount", teamPlayerCount },
            { "LimitHeight", limitHeight },
            { "BedBreakCount", bedBreakCount },
            { "Resource", resourceSet },
            { "LimitCoordStart", limitCoordStart },
            { "LimitCoordEnd", limitCoordEnd }};

        nlohmann::json &ranksDataJson = jsonData["RanksData"];
        for(uint8_t index = 0; index < 4; index++)
        {
            nlohmann::json ranksJson = {
                { "JoinSignPoint",  teamData[index].joinSignPoint },
                { "StartPoint",     teamData[index].startPosition },
                { "BedPoint",       teamData[index].bedPoint }
            };
            ranksDataJson.push_back(ranksJson);
        }

        Utils::SaveTextFile(fmt::format("{}/WildernessEscape.json", pluginDataPath), jsonData.dump());
    }

    void WildernessEscapeCore::getCmds(std::vector<std::string> &cmdVec)
    {
        cmdVec.push_back("/we");
    }
    const std::string &WildernessEscapeCore::getPluginName()
    {
        static const std::string pluginName = "荒野逃生插件";
        return pluginName;
    }
    const std::string &WildernessEscapeCore::getIntroduce()
    {
        static const std::string introduce = "\n/we help - 查看荒野逃生指令帮助";
        return introduce;
    }
    uint32_t WildernessEscapeCore::getUseAuthLevel()
    {
        return 100;
    }
    AuthDisplayType WildernessEscapeCore::getDisplayType()
    {
        return AuthDisplayType::Authority;
    }
} // namespace WE

extern "C" void initialize()
{
    PocketSurvival::GameSingleton::singletonPtr->getSingleton<PocketSurvival::PluginsManager>()->registerPlugin<WE::WildernessEscapeCore>();
    Log::Info("成功加载 荒野逃生 插件");
}